package com.xbongbong.paas.service.team.strategy;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Streams;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.help.subform.WarehouseTeamTransferSubForm;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.parent.interfaces.TeamStrategy;
import com.xbongbong.pro.detailtab.dto.team.TeamDetailEditLabelDTO;
import com.xbongbong.pro.detailtab.dto.team.TeamDetailUpdateDTO;
import com.xbongbong.pro.detailtab.vo.team.TeamDetailEditCoPerVO;
import com.xbongbong.pro.detailtab.vo.team.TeamDetailEditLabelVO;
import com.xbongbong.pro.domain.entity.FormTeamSetEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.domain.entity.UpdateDataValueEntity;
import com.xbongbong.pro.enums.DataTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.enums.teammembers.enums.FormPatternEnum;
import com.xbongbong.pro.listbatch.pojo.TeamBatchPojo;
import com.xbongbong.pro.team.TeamAfterFormatDTO;
import com.xbongbong.pro.team.TeamAfterVerifyDTO;
import com.xbongbong.pro.team.TeamVerifyDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.WarehouseUserEntity;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.UserTeamOperateTagEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.WarehouseEnum;
import com.xbongbong.saas.model.WarehouseModel;
import com.xbongbong.saas.model.WarehouseUserModel;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.support.WriteRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 仓库团队 策略
 * @author 魏荣杰
 *
 */
@Service
@Slf4j
public class WarehouseTeamStrategy extends AbstractTeamStrategy implements TeamStrategy {

    @Resource
    private WarehouseUserModel warehouseUserModel;
    @Resource
    private WarehouseTeamTransferSubForm warehouseTeamTransferSubForm;
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private WarehouseModel warehouseModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private UserModel userModel;

    @Override
    public List<Integer> type() {
        return Collections.singletonList(XbbRefTypeEnum.WAREHOUSE.getCode());
    }

    @Override
    public TeamAfterVerifyDTO verify(TeamVerifyDTO teamVerifyDTO) throws XbbException {
        String corpid = teamVerifyDTO.getCorpid();
        List<Long> dataIdIn = teamVerifyDTO.getDataId();
        UserVO loginUser = teamVerifyDTO.getLoginUser();
        Long formId = teamVerifyDTO.getFormId();
        Integer saasMark = teamVerifyDTO.getSaasMark();
        Integer businessType = teamVerifyDTO.getBusinessType();
        Integer distributorMark = teamVerifyDTO.getDistributorMark();
        String platform = teamVerifyDTO.getPlatform();
        Map<String, Set<String>> addMainUserMap = new HashMap<>();
        Map<String, Set<String>> delMainUserMap = new HashMap<>();
        TeamAfterVerifyDTO teamAfterVerifyDTO = new TeamAfterVerifyDTO();
        teamAfterVerifyDTO.setLoginUser(loginUser);
        teamAfterVerifyDTO.setCorpid(corpid);
        teamAfterVerifyDTO.setFormId(formId);
        teamAfterVerifyDTO.setSaasMark(saasMark);
        teamAfterVerifyDTO.setBusinessType(businessType);
        teamAfterVerifyDTO.setDistributorMark(distributorMark);
        teamAfterVerifyDTO.setDataId(dataIdIn);
        teamAfterVerifyDTO.setFromBackPublic(teamVerifyDTO.getFromBackPublic());
        teamAfterVerifyDTO.setOperateTag(teamVerifyDTO.getOperateTag());
        FormTeamSetEntity formTeamSetEntity = new FormTeamSetEntity();
        formTeamSetEntity.setModel(FormPatternEnum.FORM_SHARE.getModel());
        teamAfterVerifyDTO.setFormTeamSetEntity(formTeamSetEntity);
        //获取主数据相关集合，主要用于提示使用
        Map<Long, String> nameOrSeriNoMap = new HashMap<>();
        Map<Long, PaasFormDataEntity> paasFormDataEntityMap = userTeamHelp.getEntityMap(businessType, dataIdIn, corpid, nameOrSeriNoMap, saasMark);
        List<WarehouseUserEntity> warehouseUserEntities = warehouseUserModel.getUserListByTypeAndDataIdIn(corpid, BasicConstant.ZERO, dataIdIn, null);
        Map<Long, Set<String>> oldDataIdAndUserMap = new HashMap<>();
        for (WarehouseUserEntity warehouseUserEntity : warehouseUserEntities) {
            oldDataIdAndUserMap.computeIfAbsent(warehouseUserEntity.getDataId(), v -> new HashSet<>()).add(warehouseUserEntity.getRelationId());
        }
        List<TeamBatchPojo> teamBatchPojos = new ArrayList<>();
        if (Objects.equals(teamVerifyDTO.getOperateTag(), UserTeamOperateTagEnum.HANDOVER.getOperateTag())) {
            for (Long dataId : dataIdIn) {
                String changeUserId = teamVerifyDTO.getChangeUserId();
                String originUserId = teamVerifyDTO.getOriginUserId();
                Set<String> oldMainSet = oldDataIdAndUserMap.get(dataId);
                if (StringUtil.isEmpty(originUserId)) {
                    if (CollectionsUtil.isNotEmpty(oldMainSet)) {
                        originUserId = oldMainSet.stream().findFirst().get();
                    }
                }
                if (CollectionsUtil.isEmpty(oldMainSet)) {
                    oldMainSet = new HashSet<>();
                }
                if (oldMainSet.contains(changeUserId)) {
                    String errorName = nameOrSeriNoMap.get(dataId);
                    TeamBatchPojo teamBatchPojo = new TeamBatchPojo(UserTeamErrorCodeEnum.API_ERROR_271018.getCode(), UserTeamErrorCodeEnum.API_ERROR_271018.getMsg(),
                            errorName, OperateTypeEnum.HANDOVER.getName(), dataId);
                    teamBatchPojos.add(teamBatchPojo);
                    continue;
                }
                if (oldMainSet.size() > BasicConstant.ONE && Objects.equals(PlatFormEnum.WEB.getValue(), platform)) {
                    String errorName = nameOrSeriNoMap.get(dataId);
                    TeamBatchPojo teamBatchPojo = new TeamBatchPojo(UserTeamErrorCodeEnum.API_ERROR_271016.getCode(), UserTeamErrorCodeEnum.API_ERROR_271016.getMsg(),
                            errorName, OperateTypeEnum.HANDOVER.getName(), dataId);
                    teamBatchPojos.add(teamBatchPojo);
                    continue;
                }
                if (Objects.equals(originUserId, changeUserId)) {
                    String errorName = nameOrSeriNoMap.get(dataId);
                    TeamBatchPojo teamBatchPojo = new TeamBatchPojo(UserTeamErrorCodeEnum.API_ERROR_271017.getCode(), UserTeamErrorCodeEnum.API_ERROR_271017.getMsg(),
                            errorName, OperateTypeEnum.HANDOVER.getName(), dataId);
                    teamBatchPojos.add(teamBatchPojo);
                    continue;
                }
                addMainUserMap.put(dataId.toString(), new HashSet<>(Collections.singletonList(changeUserId)));
                delMainUserMap.put(dataId.toString(), new HashSet<>(Collections.singletonList(originUserId)));
            }
            teamAfterVerifyDTO.setTeamBatchPojos(teamBatchPojos);
            teamAfterVerifyDTO.setAddMainUserMap(addMainUserMap);
            teamAfterVerifyDTO.setDelMainUserMap(delMainUserMap);
            Map<String, Set<String>> updateToMainUserMap = new HashMap<>();
            teamAfterVerifyDTO.setUpdateToMainUserMap(updateToMainUserMap);
            teamAfterVerifyDTO.setPaasFormDataEntityExtMap(paasFormDataEntityMap);
        }else {
            //仓库还有添加负责人、删除负责人的功能，首先需要检验一下离职人的存在的场景；
            for (Long dataId : dataIdIn) {
                Set<String> oldMainUserList = Objects.isNull(oldDataIdAndUserMap.get(dataId)) ? new HashSet<>() : oldDataIdAndUserMap.get(dataId);
                Set<String> oldTeam = Streams.concat(oldMainUserList.stream()).collect(Collectors.toSet());
                Set<String> newAddMainUserList = teamVerifyDTO.getNewAddMainUserList();
                Set<String> newDelMainUserList = teamVerifyDTO.getNewDelMainUserList();
                if (CollectionsUtil.isNotEmpty(newAddMainUserList)) {
                    if (CollectionsUtil.isNotEmpty(oldMainUserList)) {
                        newAddMainUserList.removeAll(oldMainUserList);
                    }
                    //判断新增负责人
                    TeamBatchPojo teamBatchPojo = checkInTeamForAdd(oldTeam, newAddMainUserList, corpid, nameOrSeriNoMap.get(dataId), UserTeamOperateTagEnum.ADD_MAIN, dataId);
                    if (Objects.nonNull(teamBatchPojo)) {
                        teamBatchPojos.add(teamBatchPojo);
                        teamAfterVerifyDTO.setTeamBatchPojos(teamBatchPojos);
                        return teamAfterVerifyDTO;
                    }
                    // 去除已经在团队中的数据
                    Set<String> copyList = new HashSet<>((Set<String>) CloneUtil.deepClone(newAddMainUserList));
                    copyList.removeAll(oldTeam);
                    addMainUserMap.put(String.valueOf(dataId), copyList);
                }
                if (CollectionsUtil.isNotEmpty(newDelMainUserList)) {
                    //判断删除负责人
                    TeamBatchPojo teamBatchPojo = checkInTeamForDel(oldMainUserList, newDelMainUserList, corpid, nameOrSeriNoMap.get(dataId), UserTeamOperateTagEnum.DEL_MAIN, dataId);
                    if (Objects.nonNull(teamBatchPojo)) {
                        teamBatchPojos.add(teamBatchPojo);
                        teamAfterVerifyDTO.setTeamBatchPojos(teamBatchPojos);
                        return teamAfterVerifyDTO;
                    }
                    delMainUserMap.put(String.valueOf(dataId), newDelMainUserList);
                }
            }
            teamAfterVerifyDTO.setAddMainUserMap(addMainUserMap);
            teamAfterVerifyDTO.setDelMainUserMap(delMainUserMap);
            teamAfterVerifyDTO.setPaasFormDataEntityExtMap(paasFormDataEntityMap);
        }
        return teamAfterVerifyDTO;
    }

    /**
     * Description: 判断要新增的人员是否已经在团队中（增加负责人不能在协同人中，增加协同人不能在负责人中）在tab中操作使用
     * @param oldUserList
     * @param newAddUserList
     * @param corpid
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2021/12/30 22:25
     * @since
     */
    private TeamBatchPojo checkInTeamForAdd(Set<String> oldUserList, Set<String> newAddUserList, String corpid, String errorName, UserTeamOperateTagEnum userTeamOperateTagEnum, Long dataId) throws XbbException {
        TeamBatchPojo teamBatchPojo = null;
        oldUserList.retainAll(newAddUserList);
        if (CollectionUtils.isNotEmpty(oldUserList)) {
            List<UserEntity> userEntityList = userModel.getByUserIdIn(corpid, oldUserList, true);
            if (CollectionsUtil.isEmpty(userEntityList)) {
                return teamBatchPojo;
            }
            StringBuilder errorUserName = new StringBuilder();
            for (UserEntity entity : userEntityList) {
                errorUserName.append(entity.getName()).append(StringConstant.COMMA);
            }

            teamBatchPojo = new TeamBatchPojo(UserTeamErrorCodeEnum.API_ERROR_271008.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271008.getMsg(), errorUserName.substring(0, errorUserName.length() - 1)),
                    errorName, UserTeamOperateTagEnum.TEAM_USER_ALL_OPERATE.getName(),dataId);
        }
        return teamBatchPojo;
    }

    /**
     * Description: 判断要删除的人员是否存在负责/协同团队中
     * @param oldUserList
     * @param newDelUserList
     * @param corpid
     * @param errorName
     * @param userTeamOperateTagEnum
     * @param dataId
     * @return void
     * @throws
     * @author 魏荣杰
     * @date 2021/12/30 22:25
     * @since
     */
    private TeamBatchPojo checkInTeamForDel(Set<String> oldUserList, Set<String> newDelUserList, String corpid, String errorName, UserTeamOperateTagEnum userTeamOperateTagEnum, Long dataId) throws XbbException {
        TeamBatchPojo teamBatchPojo = null;
        if (CollectionUtils.isNotEmpty(newDelUserList)) {
            //记录不存在团队中的人
            List<String> userList = new ArrayList<>();
            if(CollectionUtils.isNotEmpty(oldUserList)){
                for (String userId : newDelUserList) {
                    if(!oldUserList.contains(userId)){
                        userList.add(userId);
                    }
                }
            }else{
                userList.addAll(newDelUserList);
            }
            List<UserEntity> userEntityList = userModel.getByUserIdIn(corpid, userList, true);
            if (CollectionsUtil.isEmpty(userEntityList)) {
                return teamBatchPojo;
            }
            StringBuilder errorUserName = new StringBuilder();
            for (UserEntity entity : userEntityList) {
                errorUserName.append(entity.getName()).append(StringConstant.COMMA);
            }
            teamBatchPojo = new TeamBatchPojo();
            if(Objects.equals(userTeamOperateTagEnum,UserTeamOperateTagEnum.DEL_MAIN)) {
                teamBatchPojo.setCode(UserTeamErrorCodeEnum.API_ERROR_271010.getCode());
                commonHelp.singleFailMsg(errorName, userTeamOperateTagEnum.getName(), teamBatchPojo);
                teamBatchPojo.setFailMsgReason(String.format(UserTeamErrorCodeEnum.API_ERROR_271010.getMsg(), errorUserName.substring(0, errorUserName.length() - 1)));
            }
            teamBatchPojo.setDataId(dataId);
        }
        return teamBatchPojo;
    }


    @Override
    public TeamAfterVerifyDTO specialVerify(TeamAfterVerifyDTO teamAfterVerifyDTO) throws XbbException {
        return teamAfterVerifyDTO;
    }

    @Override
    public void save(TeamAfterVerifyDTO teamAfterVerifyDTO) throws XbbException {
        String corpid = teamAfterVerifyDTO.getCorpid();
        Integer businessType = teamAfterVerifyDTO.getBusinessType();
        List<Long> dataId = teamAfterVerifyDTO.getDataId();

        TeamAfterFormatDTO teamAfterFormatDTO = formatTeam(teamAfterVerifyDTO);


        List<UserTeamEntity> addUserTeamList = teamAfterFormatDTO.getAddUserTeamList();
        if (CollectionsUtil.isNotEmpty(addUserTeamList)) {
            List<WarehouseUserEntity> warehouseUserEntityList = warehouseTeamTransferSubForm.transferUserTeamUserToWarehouseUser(addUserTeamList);
            warehouseUserModel.insertBatch(warehouseUserEntityList, false);
        }

        List<UserTeamEntity> delUserTeamList = teamAfterFormatDTO.getDelUserTeamList();
        if (CollectionsUtil.isNotEmpty(delUserTeamList)) {
            List<Long> idIn = delUserTeamList.stream().map(UserTeamEntity::getId).collect(Collectors.toList());
            warehouseUserModel.batchUpdateByUserIdIn(corpid, idIn, DelEnum.DELETE.getDel());
        }

        // 仓库团队这边特殊处理，因为仓库的负责人是在主表Data中的，所以团队表和主表都要更新
        List<PaasFormDataEntityExt> byDataIdList = formDataHelp.getByDataIdList(dataId, businessType, SaasMarkEnum.SAAS.getCode(), null, corpid);

        long now = DateTimeUtil.getInt();
        List<UpdateDataEntity> updateDataEntities = new ArrayList<>();

        Map<String, Set<String>> addMainUserMap = teamAfterVerifyDTO.getAddMainUserMap();
        Map<String, Set<String>> delMainUserMap = teamAfterVerifyDTO.getDelMainUserMap();
        for (PaasFormDataEntityExt paasFormDataEntityExt : byDataIdList) {
            JSONObject data = paasFormDataEntityExt.getData();
            JSONArray managerIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, WarehouseEnum.MANAGER_ID.getAttr(), new JSONArray());

            Set<String> updateUserIdIn = delMainUserMap.getOrDefault(paasFormDataEntityExt.getId().toString(), new HashSet<>());

            if(CollectionsUtil.isNotEmpty(managerIds)){
                updateUserIdIn.forEach(userId -> {
                    managerIds.removeIf(item -> Objects.equals(item.toString(), userId));
                });
            }
            Set<String> addUserIds = addMainUserMap.getOrDefault(paasFormDataEntityExt.getId().toString(), new HashSet<>());
            managerIds.addAll(addUserIds);

            UpdateDataEntity updateDataEntity = new UpdateDataEntity();
            updateDataEntity.setId(paasFormDataEntityExt.getId());
            updateDataEntity.setCorpid(corpid);
            updateDataEntity.setFormId(paasFormDataEntityExt.getFormId());
            updateDataEntity.setUpdateTime(now);
            List<UpdateDataValueEntity> dataValueEntities = new ArrayList<>();
            UpdateDataValueEntity updateDataValueEntity = new UpdateDataValueEntity();
            updateDataValueEntity.setKey(WarehouseEnum.MANAGER_ID.getAttr());
            updateDataValueEntity.setEsKey(WarehouseEnum.MANAGER_ID.getAttr());
            updateDataValueEntity.setValue(managerIds);
            updateDataValueEntity.setDataType(DataTypeEnum.JSON_ARRAY.getDataType());
            dataValueEntities.add(updateDataValueEntity);
            updateDataEntity.setData(dataValueEntities);
            updateDataEntities.add(updateDataEntity);
        }

        warehouseModel.updateBatch(updateDataEntities, corpid, WriteRequest.RefreshPolicy.NONE);


    }

    @Override
    public void afterSave(TeamAfterVerifyDTO teamAfterVerifyDTO) throws XbbException {

    }

    @Override
    public void log(TeamAfterVerifyDTO teamAfterVerifyDTO) throws XbbException {
        super.log(teamAfterVerifyDTO);
    }

    @Override
    public TeamDetailEditCoPerVO editCoPermission(TeamDetailUpdateDTO teamDetailUpdateDTO) throws XbbException {
        return null;
    }

    @Override
    public TeamDetailEditLabelVO editLabel(TeamDetailEditLabelDTO teamDetailEditLabelDTO) throws XbbException {
        return null;
    }
}
